1. Field of the Invention
The present invention is generally related to computer programs and, more particularly, is related to a system and method for efficiently sharing code, specifically, generating software intermodule procedure calls.
2. Description of Related Art
As is known in the computer and software arts, an executable file is typically composed of several separately compiled object modules and libraries. In the past, all of the code necessary to build an executable file was usually linked into one monolithic file. Nowadays, it is more likely that an executable file generated by a compiler and linker will be incomplete, requiring a plurality of shared libraries (or dynamically linked libraries, in OS/2 and Windows parlance). The base executable program is linked together with any dependent shared libraries at load time to produce a complete program.
There are many advantages to the foregoing configuration and technique. In particular, common functionality, such as the standard input/output [I/O] facilities of the C language, for example, can be shared among all of the processes running on the system, rather than requiring that each have its own private copy. When a patch or bug fix is required for a routine within a shared library, the vendor can ship a new library, and all of the programs that depend on the library will automatically pick up the new code the next time they are executed, without the need for recompilation.
Unfortunately, the code sharing configuration and technique comes at the price of a performance penalty. Functions within a load module (the base image for a particular program or any shared library) can use efficient calling sequences when invoking other functions within the same load module, because the complete physical layout of the module is known at link time. Typically, the calling sequence involves a program counter relative branch from the calling function to the destination. However, calls between dynamically linked modules use more time consuming calling sequences, because the relative placement of the calling module and the called module are not known until runtime. In some embodiments, there is also an additional large performance penalty to modify code for all inter-module calls when the program is loaded.
One solution to this performance penalty problem is to introduce the notion of an import stub. Suppose that a function F in module A calls a function G in module B. The code for function F is compiled as if the code for function G is in the same module, and the displacement of the called function G in module B is left for the linker to fix up. When the linker discovers that the called function G in module B is not in the same module A, the linker creates an import stub for the called function G in module B in the calling module's module A. While there may be many calls to function G in module B from different locations in module A, all of the calls are fixed up to pass control to the same import stub. Then, at load time, only the import stubs code has to be modified.
There should be as many import stubs as the number of external functions referenced from within the module. In general, this will be less than the total number of calls to external functions, so the amount of work required at load time is reduced.
A further improvement is to have the import stub perform the symbol table lookup the first time it is invoked (i.e., "bind-on-reference"). This improvement reduces the load time overhead to zero, but it involves somewhat more work the first time the import stub is executed. The problem with this technique is that every inter-module function call has to pass control through an import stub which introduces extra overhead vis-a-vis intra-module function calls.
Heretofore, software developers have lacked a system and method for accomplishing code sharing, particularly, inter-module function calls, in an more efficient way.